package org.jeecg.modules.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.entity.Order;
import org.jeecg.modules.entity.Posi;
import org.jeecg.modules.entity.Trade;
import org.jeecg.modules.mapper.TradeMapper;
import org.jeecg.modules.service.IOrderService;
import org.jeecg.modules.service.IPosiService;
import org.jeecg.modules.service.ITradeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.utils.MultipleNumbersSum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.awt.event.ItemEvent;
import java.io.PipedReader;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 交易表 服务实现类
 * </p>
 *
 * @author zhanggm
 * @since 2023-09-15
 */
@Slf4j
@Service
public class TradeServiceImpl extends ServiceImpl<TradeMapper, Trade> implements ITradeService {

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IPosiService posiService;


    /**
     * 根据订单，对买入，卖出的股票进行交易
     * 查询订单，完成撮合交易,更新订单表、交易表、持仓表
     */
    @Scheduled(fixedDelay = 100)
    public void trade() {
        //查询买入卖出订单，未完成撮合的status=1
        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.select(Order::getId);
        queryWrapper.eq(Order::getStatus, 0);
        queryWrapper.orderByAsc(Order::getTime).orderByAsc(Order::getOcount);
        List<Order> orderList = orderService.list(queryWrapper);
        //按股票，对订单进行分组
        Map<Integer, List<Order>> orderCodeMap = orderList.stream().collect(Collectors.groupingBy(order -> order.getCode()));
        //股票撮合
        orderCodeMap.forEach((code,codeOrderList)->{
            //买卖价格相同的才能撮合
            Map<Long, List<Order>> orderPriceMap = codeOrderList.stream().collect(Collectors.groupingBy(order -> order.getPrice()));
            orderPriceMap.forEach((price,priceOrderList)->{
                //拆分成买入和卖出的订单
                List<Order> buyList = priceOrderList.stream().filter(item -> item.getDirection().equals(1)).collect(Collectors.toList());
                List<Order> sellList = priceOrderList.stream().filter(item -> item.getDirection().equals(2)).collect(Collectors.toList());
                //撮合数据
                buyList.forEach(buy->{
                    //撮合
                    if (!CollectionUtils.isEmpty(sellList)) {
                        log.info("buy:{},sellList:{}", buy, sellList);
                        matching(buy,sellList);
                    }
                });
            });
        });
    }

    /**
     * 撮合
     *
     * @param buy
     * @param sellList
     */
    public void matching(Order buy, List<Order> sellList) {
        List<List<Order>> combinations = MultipleNumbersSum.findCombinations(sellList, buy.getOcount());
        if (CollectionUtils.isEmpty(combinations)) {
            log.info("撮合失败");
            return;
        }
        List<Order> matchingSellList = combinations.get(0);
        log.info("buy:{}", buy);
        log.info("sellList:{}", sellList);
        //删除已经撮合成功的数据
//        sellList.removeAll(matchingSellList);
        //入库
        toTrade(buy, matchingSellList);
    }


    /**
     * 更新交易
     * @param buy
     * @param sellOrderList
     */
    @Transactional(rollbackFor = Exception.class)
    public void toTrade(Order buy, List<Order> sellOrderList) {
        //修改买入订单状态
        buy.setStatus(1);
        List<Order> saveOrderList = sellOrderList.stream().map(item -> {
            return item.setStatus(1);
        }).collect(Collectors.toList());
        //批量保存
        orderService.saveOrUpdate(buy);
        orderService.saveOrUpdateBatch(saveOrderList);
        log.info("更新订单成功：{}",saveOrderList.stream().map(item->item.getId()).collect(Collectors.toList()));
        //批量更新交易表
        List<Order> tradeOrderList = new ArrayList<>(saveOrderList);
        tradeOrderList.add(buy);
        List<Trade> tradeList = new ArrayList<>();
        tradeOrderList.forEach(order -> {
            Trade trade = new Trade().setUid(order.getUid())
                    .setCode(order.getCode())
                    .setDirection(order.getDirection())
                    .setDate(order.getDate())
                    .setTime(order.getTime())
                    .setPrice(order.getPrice())
                    .setOid(order.getId())
                    .setTcount(order.getOcount());
            tradeList.add(trade);
        });
        this.saveBatch(tradeList);
        log.info("更新交易成功：{}",tradeList.stream().map(item->item.getId()).collect(Collectors.toList()));
        //批量跟新持仓表,查询是否有历史持仓数据
        List<Long> uidList = saveOrderList.stream().map(item -> item.getUid()).distinct().collect(Collectors.toList());
        List<Integer> codeList = saveOrderList.stream().map(item -> item.getCode()).distinct().collect(Collectors.toList());
        //查询关联的持仓表数据
        LambdaQueryWrapper<Posi> posiLambdaQueryWrapper = new LambdaQueryWrapper<>();
        posiLambdaQueryWrapper.in(Posi::getUid, uidList).in(Posi::getCode, codeList)/*.notIn(Posi::getCode,buy.getCode())*/;
        List<Posi> posiList = posiService.list(posiLambdaQueryWrapper);
        //更新历史持仓数据，不包含买的
         for (Posi posi : posiList) {
             log.info("posi:{}",posi);
            Stream<Order> orderStream = saveOrderList.stream().filter(item -> item.getUid().equals(posi.getUid()) && item.getCode().equals(posi.getCode()) && item.getDirection().equals(2));
            //计算持仓数量
            long ocount = orderStream.mapToLong(item -> item.getOcount()).sum();
            posi.setCount(posi.getCount() - ocount);
            //计算成本
            long nowMoney = saveOrderList.stream().filter(item -> item.getUid().equals(posi.getUid()) && item.getCode().equals(posi.getCode())).mapToLong(item -> item.getPrice() * item.getOcount()).sum();
            long hisMoney = posi.getCost().longValue() * posi.getCount().longValue();
            long cost = (hisMoney - nowMoney) / posi.getCount();
            posi.setCost(cost);
             log.info("posi:{}",posi);
        }
        posiService.updateBatchById(posiList);
        log.info("更新持仓成功：{}",posiList.stream().map(item->item.getId()).collect(Collectors.toList()));
        //处理新增交易的持仓,对两个集合求差集
        //List<Order> differenceList = saveOrderList.stream().filter(item -> !posiList.contains(item) || item.getDirection().equals(1)).collect(Collectors.toList());
//        Optional<Posi> any = posiList.stream().filter(item -> item.getUid().equals(buy.getUid()) && item.getCode().equals(buy.getCode())).findAny();
        LambdaQueryWrapper<Posi> buyLambdaQueryWrapper = new LambdaQueryWrapper<>();
        buyLambdaQueryWrapper.eq(Posi::getUid, buy.getUid()).eq(Posi::getCode, buy.getCode());
        Posi posi = posiService.getOne(buyLambdaQueryWrapper);//posiList.stream().filter(item -> item.getUid().equals(buy.getUid()) && item.getCount().equals(buy.getCode())).collect(Collectors.toList()).get(0);
        if (posi == null) {
            posi = new Posi().setUid(buy.getUid()).setCode(buy.getCode()).setCost(buy.getPrice()).setCount(buy.getOcount());
        } else {
            posi.setUid(buy.getUid());
            posi.setCode(buy.getCode());
            //计算持仓数量
            posi.setCount(posi.getCount() + buy.getOcount());
            //计算成本
            long hisMoney = posi.getCost() * posi.getCount();
            long nowMoney = buy.getPrice().longValue() * buy.getOcount();
            long cost = (hisMoney + nowMoney) / posi.getCount();
            posi.setCost(cost);
        }
        posiService.saveOrUpdate(posi);
        log.info("买入交易成功：{}",posi);

    }




}
